package org.edu.common.base;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * dto-page对象，P为参数，R为返回类一般为实体类
 *
 */
@Data
public class BasePageDto<P, R> implements IPage<R>, Serializable {
    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 1814729350900415038L;

    /**
     * 开始页从1开始
     */
    @ApiModelProperty(value = "当前页")
    private long current;

    /**
     * 每页数量
     */
    @ApiModelProperty(value = "每页数量")
    private long size;

    /**
     * 总数
     */
    @ApiModelProperty(hidden = true)
    private long total;

    /**
     * 记录
     */
    @ApiModelProperty(hidden = true)
    private List<R> records;

    /**
     * 排序
     */
    @ApiModelProperty("排序")
    private List<OrderItemDto> sorts;

    /**
     * 查询条件
     */
    @ApiModelProperty("查询条件")
    private List<ConditionDto> conditions;

    /**
     * 自定义查询参数对象
     */
    @ApiModelProperty("自定义查询参数对象")
    private P param;

    public BasePageDto() {
    }

    public BasePageDto(long current, long size) {
        this.current = current;
        this.size = size;
    }

    @Override
    public IPage<R> setSize(long l) {
        this.size = l;
        return this;
    }

    @Override
    public IPage<R> setCurrent(long l) {
        this.current = l;
        return this;
    }

    @Override
    public IPage<R> setTotal(long total) {
        this.total = total;
        return this;
    }

    @Override
    public long getTotal() {
        return total;
    }

    @Override
    public IPage<R> setRecords(List<R> records) {
        this.records = records;
        return this;
    }

    @Override
    public List<R> getRecords() {
        return records;
    }

    @Override
    public List<OrderItem> orders() {
        List<OrderItem> list = new ArrayList<>();
        if (sorts != null) {
            for (OrderItemDto orderItemDto : sorts) {
                if (StrUtil.isNotBlank(orderItemDto.getColumn())) {
                    if (orderItemDto.isAsc()) {
                        list.add(OrderItem.asc(orderItemDto.getColumn()));
                    } else {
                        list.add(OrderItem.desc(orderItemDto.getColumn()));
                    }
                }
            }
        }
        return list;
    }

    /**
     * 构造查询条件
     *
     * @param tClass entity class
     * @return Specification

     * @since 2020-04-02
     */
    public <E> QueryWrapper<E> buildQueryWrapper(Class<E> tClass) {
        QueryWrapper<E> queryWrapper = new QueryWrapper<>();
        fillConditions(queryWrapper, conditions);
        buildOrderBy(queryWrapper);
        return queryWrapper;
    }

    /**
     * 填充查询条件
     *
     * @param queryWrapper
     * @param list
     * @return

     * @since 2020-04-02
     */
    private <E> QueryWrapper<E> fillConditions(QueryWrapper<E> queryWrapper, List<ConditionDto> list) {
        if (list != null) {
            for (ConditionDto condition : list) {
                //StringUtil.humpToLine(condition.getColumn());
                if (!Objects.isNull(condition.getOperator()) && StrUtil.isNotBlank(condition.getColumn())) {
                    switch (condition.getOperator()) {
                        case EQ:
                            queryWrapper.eq(condition.getColumn(), condition.getValue());
                            break;
                        case NE:
                            queryWrapper.ne(condition.getColumn(), condition.getValue());
                            break;
                        case GE:
                            queryWrapper.ge(condition.getColumn(), condition.getValue());
                            break;
                        case GT:
                            queryWrapper.gt(condition.getColumn(), condition.getValue());
                            break;
                        case LE:
                            queryWrapper.le(condition.getColumn(), condition.getValue());
                            break;
                        case LT:
                            queryWrapper.lt(condition.getColumn(), condition.getValue());
                            break;
                        case GT_DATE:
                            DateTime data3 = DateUtil.parse(condition.getValue().toString(), DatePattern.NORM_DATETIME_PATTERN);
                            queryWrapper.gt(condition.getColumn(), data3);
                            break;
                        case LT_DATE:
                            DateTime data4 = DateUtil.parse(condition.getValue().toString(), DatePattern.NORM_DATETIME_PATTERN);
                            queryWrapper.lt(condition.getColumn(), data4);
                            break;
                        case BETWEEN:
                            queryWrapper.between(condition.getColumn(),
                                    condition.getBetweenValue1(), condition.getBetweenValue2());
                            break;
                        case BETWEEN_DATE:
                            DateTime data1 = DateUtil.parse(condition.getBetweenValue1().toString(), DatePattern.NORM_DATE_PATTERN);
                            DateTime data2 = DateUtil.parse(condition.getBetweenValue2().toString(), DatePattern.NORM_DATE_PATTERN);
                            queryWrapper.between(condition.getColumn(), data1, data2);
                            break;
                        case NOT_BETWEEN:
                            queryWrapper.notBetween(condition.getColumn(),
                                    condition.getBetweenValue1(), condition.getBetweenValue2());
                            break;
                        case IN:
                            queryWrapper.in(condition.getColumn(),
                                    Arrays.asList(condition.getValue().toString().split(",")));
                            break;
                        case NOT_IN:
                            queryWrapper.notIn(condition.getColumn(),
                                    Arrays.asList(condition.getValue().toString().split(",")));
                            break;
                        case IS_NOT_NULL:
                            queryWrapper.isNotNull(condition.getColumn());
                            break;
                        case IS_NULL:
                            queryWrapper.isNull(condition.getColumn());
                            break;
                        case NOT_LIKE:
                            queryWrapper.notLike(condition.getColumn(), condition.getValue());
                            break;
                        case LIKE:
                            queryWrapper.like(condition.getColumn(), condition.getValue());
                            break;
                        case LIKE_LEFT:
                            queryWrapper.likeLeft(condition.getColumn(), condition.getValue());
                            break;
                        case LIKE_RIGHT:
                            queryWrapper.likeRight(condition.getColumn(), condition.getValue());
                            break;
                        case AND:
                            queryWrapper.and(q -> fillConditions(q, condition.getChildren()));
                            break;
                        case OR:
                            queryWrapper.or(q -> fillConditions(q, condition.getChildren()));
                            break;
                        default:
                    }
                }
            }
        }
        return queryWrapper;
    }

    /**
     * 构造分页对象
     * 包括排序
     *
     * @return QueryWrapper

     * @since 2020-04-02
     */
    public <E> QueryWrapper<E> buildOrderBy(QueryWrapper<E> queryWrapper) {
        if (sorts != null) {
            for (OrderItemDto orderItemDto : sorts) {
                if (StrUtil.isNotBlank(orderItemDto.getColumn())) {
                    if (orderItemDto.isAsc()) {
                        queryWrapper.orderByAsc(orderItemDto.getColumn());
                    } else {
                        queryWrapper.orderByDesc(orderItemDto.getColumn());
                    }
                }
            }
        }
        return queryWrapper;
    }
}
